package cn.vconinfo.database.inner.config;

import cn.vconinfo.database.aspect.DynamicDataSourceContextHolder;
import cn.vconinfo.database.handler.DynamicDataSource;
import cn.vconinfo.database.inner.enums.DataSourceTypeEnum;
import com.alibaba.druid.pool.DruidDataSourceFactory;
import org.apache.commons.lang3.StringUtils;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DependsOn;
import org.springframework.context.annotation.Primary;
import org.springframework.core.env.Environment;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;

import javax.sql.DataSource;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.Properties;

/**
 * Title:MybatisConfiguration
 *
 * @author angla
 **/
@Configuration
//@ConfigurationProperties(value = "database.yml")
@ConditionalOnProperty(name="spring.config.profile", havingValue = "true", matchIfMissing = false)
public class MybatisConfiguration {
    @Autowired
    private Environment env;
    /**
     * 创建数据源(数据源的名称：方法名可以取为XXXDataSource(),XXX为数据库名称,该名称也就是数据源的名称)
     */
    @Bean
    public DataSource masterDataSource() throws Exception {
        Properties props = new Properties();
        props.put("driverClassName", env.getProperty("spring.mastersource.driver-class-name"));
        props.put("url", env.getProperty("spring.mastersource.url"));
        props.put("username", env.getProperty("spring.mastersource.username"));
        props.put("password", env.getProperty("spring.mastersource.password"));
        return DruidDataSourceFactory.createDataSource(props);
    }

    @Bean
    public DataSource slaveDataSource() throws Exception {
        Properties props = new Properties();
        props.put("driverClassName", env.getProperty("spring.slavesource.driver-class-name"));
        props.put("url", env.getProperty("spring.slavesource.url"));
        props.put("username", env.getProperty("spring.slavesource.username"));
        props.put("password", env.getProperty("spring.slavesource.password"));
        return DruidDataSourceFactory.createDataSource(props);
    }

//    @Bean
//    public DataSource obeyDataSource() throws Exception {
//        Properties props = new Properties();
//        props.put("driverClassName", env.getProperty("spring.obeysource.driver-class-name"));
//        props.put("url", env.getProperty("spring.obeysource.url"));
//        props.put("username", env.getProperty("spring.obeysource.username"));
//        props.put("password", env.getProperty("spring.obeysource.password"));
//        return DruidDataSourceFactory.createDataSource(props);
//    }

    /**
     * @Primary 该注解表示在同一个接口有多个实现类可以注入的时候，默认选择哪一个，而不是让@autowire注解报错
     * @Qualifier 根据名称进行注入，通常是在具有相同的多个类型的实例的一个注入（例如有多个DataSource类型的实例）
     */
    @Bean
    @Primary
//    @DependsOn({"masterDataSource", "slaveDataSource", "obeyDataSource"})
    @DependsOn({"masterDataSource", "slaveDataSource"})
    public DynamicDataSource dataSource(DataSource masterDataSource, DataSource slaveDataSource) {
        Map<Object, Object> targetDataSources = new HashMap<>();
        targetDataSources.put(DataSourceTypeEnum.DATA_SOURCE_MASTER.getCode(), masterDataSource);
        targetDataSources.put(DataSourceTypeEnum.DATA_SOURCE_SLAVE.getCode(), slaveDataSource);
//        targetDataSources.put(DataSourceTypeEnum.DATA_SOURCE_OBEY.getCode(), obeyDataSource);

        DynamicDataSourceContextHolder.dataSourceIds.add(DataSourceTypeEnum.DATA_SOURCE_MASTER.getCode());
        DynamicDataSourceContextHolder.dataSourceIds.add(DataSourceTypeEnum.DATA_SOURCE_SLAVE.getCode());
//        DynamicDataSourceContextHolder.dataSourceIds.add(DataSourceTypeEnum.DATA_SOURCE_OBEY.getCode());

        DynamicDataSource dataSource = new DynamicDataSource();
        dataSource.setTargetDataSources(targetDataSources);// 该方法是AbstractRoutingDataSource的方法
        dataSource.setDefaultTargetDataSource(masterDataSource);// 默认的datasource设置为myTestDbDataSource

        return dataSource;
    }

    /**
     * 根据数据源创建SqlSessionFactory
     */
    @Bean
    public SqlSessionFactory sqlSessionFactory(DynamicDataSource ds, @Autowired org.apache.ibatis.session.Configuration configuration) throws Exception {
        SqlSessionFactoryBean fb = new SqlSessionFactoryBean();
        fb.setDataSource(ds);// 指定数据源
        if(StringUtils.isNotBlank(env.getProperty("mybatis.typeAliasesPackage"))){
            fb.setTypeAliasesPackage(env.getProperty("mybatis.typeAliasesPackage"));// 指定基包
        }
        String mapperLocations = env.getProperty("mybatis.mapperLocations");
        if(StringUtils.isBlank(mapperLocations)){
            mapperLocations = env.getProperty("mybatis.mapper-locations");
        }
        if(StringUtils.isNotBlank(mapperLocations)){
            fb.setMapperLocations(
                    new PathMatchingResourcePatternResolver().getResources(Objects.requireNonNull(mapperLocations)));
        }

        // 重写了factory导致mybatis配置需要手工导入
        if(configuration != null){
            fb.setConfiguration(configuration);
        }

        return fb.getObject();
    }

}
